import { isNonEmptyString, isNullOrUndefined } from '@sindresorhus/is';
import { logger } from '../../../logger';
import { regEx } from '../../../util/regex';
import { PypiDatasource } from '../../datasource/pypi';
import { normalizePythonDepName } from '../../datasource/pypi/common';
import type { PackageDependency } from '../types';
import type { Pep508ParseResult } from './types';

const pep508Regex = regEx(
  /^(?<packageName>[A-Z0-9._-]+)\s*(\[(?<extras>[A-Z0-9\s,._-]+)\])?\s*(?<currentValue>[^;]+)?(;\s*(?<marker>.*))?/i,
);

export const depTypes = {
  dependencies: 'project.dependencies',
  optionalDependencies: 'project.optional-dependencies',
  dependencyGroups: 'dependency-groups',
  pdmDevDependencies: 'tool.pdm.dev-dependencies',
  uvDevDependencies: 'tool.uv.dev-dependencies',
  uvSources: 'tool.uv.sources',
  buildSystemRequires: 'build-system.requires',
};

export function parsePEP508(
  value: string | null | undefined,
): Pep508ParseResult | null {
  if (isNullOrUndefined(value)) {
    return null;
  }

  const regExpExec = pep508Regex.exec(value);
  if (isNullOrUndefined(regExpExec) || isNullOrUndefined(regExpExec?.groups)) {
    logger.trace(`Pep508 could not be extracted`);
    return null;
  }

  const result: Pep508ParseResult = {
    packageName: regExpExec.groups.packageName,
  };
  if (isNonEmptyString(regExpExec.groups.currentValue)) {
    if (
      regExpExec.groups.currentValue.startsWith('(') &&
      regExpExec.groups.currentValue.endsWith(')')
    ) {
      result.currentValue = regExpExec.groups.currentValue.slice(1, -1).trim();
    } else {
      result.currentValue = regExpExec.groups.currentValue;
    }
  }

  if (isNonEmptyString(regExpExec.groups.marker)) {
    result.marker = regExpExec.groups.marker;
  }
  if (isNonEmptyString(regExpExec.groups.extras)) {
    // trim to remove allowed whitespace between brackets
    result.extras = regExpExec.groups.extras.split(',').map((e) => e.trim());
  }

  return result;
}

export function pep508ToPackageDependency(
  depType: string,
  value: string,
): PackageDependency | null {
  const parsed = parsePEP508(value);
  if (isNullOrUndefined(parsed)) {
    return null;
  }

  const dep: PackageDependency = {
    packageName: normalizePythonDepName(parsed.packageName),
    depName: parsed.packageName,
    datasource: PypiDatasource.id,
    depType,
  };

  if (isNullOrUndefined(parsed.currentValue)) {
    dep.skipReason = 'unspecified-version';
  } else {
    dep.currentValue = parsed.currentValue;

    if (parsed.currentValue.startsWith('==')) {
      dep.currentVersion = parsed.currentValue.replace(regEx(/^==\s*/), '');
    }
  }
  return dep;
}
